1   /*
2    * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved.
3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4    *
5    * This code is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU General Public License version 2 only, as
7    * published by the Free Software Foundation.  Oracle designates this
8    * particular file as subject to the "Classpath" exception as provided
9    * by Oracle in the LICENSE file that accompanied this code.
10   *
11   * This code is distributed in the hope that it will be useful, but WITHOUT
12   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14   * version 2 for more details (a copy is included in the LICENSE file that
15   * accompanied this code).
16   *
17   * You should have received a copy of the GNU General Public License version
18   * 2 along with this work; if not, write to the Free Software Foundation,
19   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20   *
21   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22   * or visit www.oracle.com if you need additional information or have any
23   * questions.
24   */
25  
26  package javax.swing.table;
27  
28  import java.io.Serializable;
29  import java.util.Vector;
30  import java.util.Enumeration;
31  import javax.swing.event.TableModelEvent;
32  
33  
34  /**
35   * This is an implementation of <code>TableModel</code> that
36   * uses a <code>Vector</code> of <code>Vectors</code> to store the
37   * cell value objects.
38   * <p>
39   * <strong>Warning:</strong> <code>DefaultTableModel</code> returns a
40   * column class of <code>Object</code>.  When
41   * <code>DefaultTableModel</code> is used with a
42   * <code>TableRowSorter</code> this will result in extensive use of
43   * <code>toString</code>, which for non-<code>String</code> data types
44   * is expensive.  If you use <code>DefaultTableModel</code> with a
45   * <code>TableRowSorter</code> you are strongly encouraged to override
46   * <code>getColumnClass</code> to return the appropriate type.
47   * <p>
48   * <strong>Warning:</strong>
49   * Serialized objects of this class will not be compatible with
50   * future Swing releases. The current serialization support is
51   * appropriate for short term storage or RMI between applications running
52   * the same version of Swing.  As of 1.4, support for long term storage
53   * of all JavaBeans<sup><font size="-2">TM</font></sup>
54   * has been added to the <code>java.beans</code> package.
55   * Please see {@link java.beans.XMLEncoder}.
56   *
57   * @author Philip Milne
58   *
59   * @see TableModel
60   * @see #getDataVector
61   */
62  public class DefaultTableModel extends AbstractTableModel implements Serializable {
63  
64  //
65  // Instance Variables
66  //
67  
68      /**
69       * The <code>Vector</code> of <code>Vectors</code> of
70       * <code>Object</code> values.
71       */
72      protected Vector    dataVector;
73  
74      /** The <code>Vector</code> of column identifiers. */
75      protected Vector    columnIdentifiers;
76  
77  //
78  // Constructors
79  //
80  
81      /**
82       *  Constructs a default <code>DefaultTableModel</code>
83       *  which is a table of zero columns and zero rows.
84       */
85      public DefaultTableModel() {
86          this(0, 0);
87      }
88  
89      private static Vector newVector(int size) {
90          Vector v = new Vector(size);
91          v.setSize(size);
92          return v;
93      }
94  
95      /**
96       *  Constructs a <code>DefaultTableModel</code> with
97       *  <code>rowCount</code> and <code>columnCount</code> of
98       *  <code>null</code> object values.
99       *
100      * @param rowCount           the number of rows the table holds
101      * @param columnCount        the number of columns the table holds
102      *
103      * @see #setValueAt
104      */
105     public DefaultTableModel(int rowCount, int columnCount) {
106         this(newVector(columnCount), rowCount);
107     }
108 
109     /**
110      *  Constructs a <code>DefaultTableModel</code> with as many columns
111      *  as there are elements in <code>columnNames</code>
112      *  and <code>rowCount</code> of <code>null</code>
113      *  object values.  Each column's name will be taken from
114      *  the <code>columnNames</code> vector.
115      *
116      * @param columnNames       <code>vector</code> containing the names
117      *                          of the new columns; if this is
118      *                          <code>null</code> then the model has no columns
119      * @param rowCount           the number of rows the table holds
120      * @see #setDataVector
121      * @see #setValueAt
122      */
123     public DefaultTableModel(Vector columnNames, int rowCount) {
124         setDataVector(newVector(rowCount), columnNames);
125     }
126 
127     /**
128      *  Constructs a <code>DefaultTableModel</code> with as many
129      *  columns as there are elements in <code>columnNames</code>
130      *  and <code>rowCount</code> of <code>null</code>
131      *  object values.  Each column's name will be taken from
132      *  the <code>columnNames</code> array.
133      *
134      * @param columnNames       <code>array</code> containing the names
135      *                          of the new columns; if this is
136      *                          <code>null</code> then the model has no columns
137      * @param rowCount           the number of rows the table holds
138      * @see #setDataVector
139      * @see #setValueAt
140      */
141     public DefaultTableModel(Object[] columnNames, int rowCount) {
142         this(convertToVector(columnNames), rowCount);
143     }
144 
145     /**
146      *  Constructs a <code>DefaultTableModel</code> and initializes the table
147      *  by passing <code>data</code> and <code>columnNames</code>
148      *  to the <code>setDataVector</code> method.
149      *
150      * @param data              the data of the table, a <code>Vector</code>
151      *                          of <code>Vector</code>s of <code>Object</code>
152      *                          values
153      * @param columnNames       <code>vector</code> containing the names
154      *                          of the new columns
155      * @see #getDataVector
156      * @see #setDataVector
157      */
158     public DefaultTableModel(Vector data, Vector columnNames) {
159         setDataVector(data, columnNames);
160     }
161 
162     /**
163      *  Constructs a <code>DefaultTableModel</code> and initializes the table
164      *  by passing <code>data</code> and <code>columnNames</code>
165      *  to the <code>setDataVector</code>
166      *  method. The first index in the <code>Object[][]</code> array is
167      *  the row index and the second is the column index.
168      *
169      * @param data              the data of the table
170      * @param columnNames       the names of the columns
171      * @see #getDataVector
172      * @see #setDataVector
173      */
174     public DefaultTableModel(Object[][] data, Object[] columnNames) {
175         setDataVector(data, columnNames);
176     }
177 
178     /**
179      *  Returns the <code>Vector</code> of <code>Vectors</code>
180      *  that contains the table's
181      *  data values.  The vectors contained in the outer vector are
182      *  each a single row of values.  In other words, to get to the cell
183      *  at row 1, column 5: <p>
184      *
185      *  <code>((Vector)getDataVector().elementAt(1)).elementAt(5);</code><p>
186      *
187      * @return  the vector of vectors containing the tables data values
188      *
189      * @see #newDataAvailable
190      * @see #newRowsAdded
191      * @see #setDataVector
192      */
193     public Vector getDataVector() {
194         return dataVector;
195     }
196 
197     private static Vector nonNullVector(Vector v) {
198         return (v != null) ? v : new Vector();
199     }
200 
201     /**
202      *  Replaces the current <code>dataVector</code> instance variable
203      *  with the new <code>Vector</code> of rows, <code>dataVector</code>.
204      *  Each row is represented in <code>dataVector</code> as a
205      *  <code>Vector</code> of <code>Object</code> values.
206      *  <code>columnIdentifiers</code> are the names of the new
207      *  columns.  The first name in <code>columnIdentifiers</code> is
208      *  mapped to column 0 in <code>dataVector</code>. Each row in
209      *  <code>dataVector</code> is adjusted to match the number of
210      *  columns in <code>columnIdentifiers</code>
211      *  either by truncating the <code>Vector</code> if it is too long,
212      *  or adding <code>null</code> values if it is too short.
213      *  <p>Note that passing in a <code>null</code> value for
214      *  <code>dataVector</code> results in unspecified behavior,
215      *  an possibly an exception.
216      *
217      * @param   dataVector         the new data vector
218      * @param   columnIdentifiers     the names of the columns
219      * @see #getDataVector
220      */
221     public void setDataVector(Vector dataVector, Vector columnIdentifiers) {
222         this.dataVector = nonNullVector(dataVector);
223         this.columnIdentifiers = nonNullVector(columnIdentifiers);
224         justifyRows(0, getRowCount());
225         fireTableStructureChanged();
226     }
227 
228     /**
229      *  Replaces the value in the <code>dataVector</code> instance
230      *  variable with the values in the array <code>dataVector</code>.
231      *  The first index in the <code>Object[][]</code>
232      *  array is the row index and the second is the column index.
233      *  <code>columnIdentifiers</code> are the names of the new columns.
234      *
235      * @param dataVector                the new data vector
236      * @param columnIdentifiers the names of the columns
237      * @see #setDataVector(Vector, Vector)
238      */
239     public void setDataVector(Object[][] dataVector, Object[] columnIdentifiers) {
240         setDataVector(convertToVector(dataVector), convertToVector(columnIdentifiers));
241     }
242 
243     /**
244      *  Equivalent to <code>fireTableChanged</code>.
245      *
246      * @param event  the change event
247      *
248      */
249     public void newDataAvailable(TableModelEvent event) {
250         fireTableChanged(event);
251     }
252 
253 //
254 // Manipulating rows
255 //
256 
257     private void justifyRows(int from, int to) {
258         // Sometimes the DefaultTableModel is subclassed
259         // instead of the AbstractTableModel by mistake.
260         // Set the number of rows for the case when getRowCount
261         // is overridden.
262         dataVector.setSize(getRowCount());
263 
264         for (int i = from; i < to; i++) {
265             if (dataVector.elementAt(i) == null) {
266                 dataVector.setElementAt(new Vector(), i);
267             }
268             ((Vector)dataVector.elementAt(i)).setSize(getColumnCount());
269         }
270     }
271 
272     /**
273      *  Ensures that the new rows have the correct number of columns.
274      *  This is accomplished by  using the <code>setSize</code> method in
275      *  <code>Vector</code> which truncates vectors
276      *  which are too long, and appends <code>null</code>s if they
277      *  are too short.
278      *  This method also sends out a <code>tableChanged</code>
279      *  notification message to all the listeners.
280      *
281      * @param e         this <code>TableModelEvent</code> describes
282      *                           where the rows were added.
283      *                           If <code>null</code> it assumes
284      *                           all the rows were newly added
285      * @see #getDataVector
286      */
287     public void newRowsAdded(TableModelEvent e) {
288         justifyRows(e.getFirstRow(), e.getLastRow() + 1);
289         fireTableChanged(e);
290     }
291 
292     /**
293      *  Equivalent to <code>fireTableChanged</code>.
294      *
295      *  @param event the change event
296      *
297      */
298     public void rowsRemoved(TableModelEvent event) {
299         fireTableChanged(event);
300     }
301 
302     /**
303      * Obsolete as of Java 2 platform v1.3.  Please use <code>setRowCount</code> instead.
304      */
305     /*
306      *  Sets the number of rows in the model.  If the new size is greater
307      *  than the current size, new rows are added to the end of the model
308      *  If the new size is less than the current size, all
309      *  rows at index <code>rowCount</code> and greater are discarded. <p>
310      *
311      * @param   rowCount   the new number of rows
312      * @see #setRowCount
313      */
314     public void setNumRows(int rowCount) {
315         int old = getRowCount();
316         if (old == rowCount) {
317             return;
318         }
319         dataVector.setSize(rowCount);
320         if (rowCount <= old) {
321             fireTableRowsDeleted(rowCount, old-1);
322         }
323         else {
324             justifyRows(old, rowCount);
325             fireTableRowsInserted(old, rowCount-1);
326         }
327     }
328 
329     /**
330      *  Sets the number of rows in the model.  If the new size is greater
331      *  than the current size, new rows are added to the end of the model
332      *  If the new size is less than the current size, all
333      *  rows at index <code>rowCount</code> and greater are discarded. <p>
334      *
335      *  @see #setColumnCount
336      * @since 1.3
337      */
338     public void setRowCount(int rowCount) {
339         setNumRows(rowCount);
340     }
341 
342     /**
343      *  Adds a row to the end of the model.  The new row will contain
344      *  <code>null</code> values unless <code>rowData</code> is specified.
345      *  Notification of the row being added will be generated.
346      *
347      * @param   rowData          optional data of the row being added
348      */
349     public void addRow(Vector rowData) {
350         insertRow(getRowCount(), rowData);
351     }
352 
353     /**
354      *  Adds a row to the end of the model.  The new row will contain
355      *  <code>null</code> values unless <code>rowData</code> is specified.
356      *  Notification of the row being added will be generated.
357      *
358      * @param   rowData          optional data of the row being added
359      */
360     public void addRow(Object[] rowData) {
361         addRow(convertToVector(rowData));
362     }
363 
364     /**
365      *  Inserts a row at <code>row</code> in the model.  The new row
366      *  will contain <code>null</code> values unless <code>rowData</code>
367      *  is specified.  Notification of the row being added will be generated.
368      *
369      * @param   row             the row index of the row to be inserted
370      * @param   rowData         optional data of the row being added
371      * @exception  ArrayIndexOutOfBoundsException  if the row was invalid
372      */
373     public void insertRow(int row, Vector rowData) {
374         dataVector.insertElementAt(rowData, row);
375         justifyRows(row, row+1);
376         fireTableRowsInserted(row, row);
377     }
378 
379     /**
380      *  Inserts a row at <code>row</code> in the model.  The new row
381      *  will contain <code>null</code> values unless <code>rowData</code>
382      *  is specified.  Notification of the row being added will be generated.
383      *
384      * @param   row      the row index of the row to be inserted
385      * @param   rowData          optional data of the row being added
386      * @exception  ArrayIndexOutOfBoundsException  if the row was invalid
387      */
388     public void insertRow(int row, Object[] rowData) {
389         insertRow(row, convertToVector(rowData));
390     }
391 
392     private static int gcd(int i, int j) {
393         return (j == 0) ? i : gcd(j, i%j);
394     }
395 
396     private static void rotate(Vector v, int a, int b, int shift) {
397         int size = b - a;
398         int r = size - shift;
399         int g = gcd(size, r);
400         for(int i = 0; i < g; i++) {
401             int to = i;
402             Object tmp = v.elementAt(a + to);
403             for(int from = (to + r) % size; from != i; from = (to + r) % size) {
404                 v.setElementAt(v.elementAt(a + from), a + to);
405                 to = from;
406             }
407             v.setElementAt(tmp, a + to);
408         }
409     }
410 
411     /**
412      *  Moves one or more rows from the inclusive range <code>start</code> to
413      *  <code>end</code> to the <code>to</code> position in the model.
414      *  After the move, the row that was at index <code>start</code>
415      *  will be at index <code>to</code>.
416      *  This method will send a <code>tableChanged</code> notification
417      *  message to all the listeners. <p>
418      *
419      *  <pre>
420      *  Examples of moves:
421      *  <p>
422      *  1. moveRow(1,3,5);
423      *          a|B|C|D|e|f|g|h|i|j|k   - before
424      *          a|e|f|g|h|B|C|D|i|j|k   - after
425      *  <p>
426      *  2. moveRow(6,7,1);
427      *          a|b|c|d|e|f|G|H|i|j|k   - before
428      *          a|G|H|b|c|d|e|f|i|j|k   - after
429      *  <p>
430      *  </pre>
431      *
432      * @param   start       the starting row index to be moved
433      * @param   end         the ending row index to be moved
434      * @param   to          the destination of the rows to be moved
435      * @exception  ArrayIndexOutOfBoundsException  if any of the elements
436      * would be moved out of the table's range
437      *
438      */
439     public void moveRow(int start, int end, int to) {
440         int shift = to - start;
441         int first, last;
442         if (shift < 0) {
443             first = to;
444             last = end;
445         }
446         else {
447             first = start;
448             last = to + end - start;
449         }
450         rotate(dataVector, first, last + 1, shift);
451 
452         fireTableRowsUpdated(first, last);
453     }
454 
455     /**
456      *  Removes the row at <code>row</code> from the model.  Notification
457      *  of the row being removed will be sent to all the listeners.
458      *
459      * @param   row      the row index of the row to be removed
460      * @exception  ArrayIndexOutOfBoundsException  if the row was invalid
461      */
462     public void removeRow(int row) {
463         dataVector.removeElementAt(row);
464         fireTableRowsDeleted(row, row);
465     }
466 
467 //
468 // Manipulating columns
469 //
470 
471     /**
472      * Replaces the column identifiers in the model.  If the number of
473      * <code>newIdentifier</code>s is greater than the current number
474      * of columns, new columns are added to the end of each row in the model.
475      * If the number of <code>newIdentifier</code>s is less than the current
476      * number of columns, all the extra columns at the end of a row are
477      * discarded. <p>
478      *
479      * @param   columnIdentifiers  vector of column identifiers.  If
480      *                          <code>null</code>, set the model
481      *                          to zero columns
482      * @see #setNumRows
483      */
484     public void setColumnIdentifiers(Vector columnIdentifiers) {
485         setDataVector(dataVector, columnIdentifiers);
486     }
487 
488     /**
489      * Replaces the column identifiers in the model.  If the number of
490      * <code>newIdentifier</code>s is greater than the current number
491      * of columns, new columns are added to the end of each row in the model.
492      * If the number of <code>newIdentifier</code>s is less than the current
493      * number of columns, all the extra columns at the end of a row are
494      * discarded. <p>
495      *
496      * @param   newIdentifiers  array of column identifiers.
497      *                          If <code>null</code>, set
498      *                          the model to zero columns
499      * @see #setNumRows
500      */
501     public void setColumnIdentifiers(Object[] newIdentifiers) {
502         setColumnIdentifiers(convertToVector(newIdentifiers));
503     }
504 
505     /**
506      *  Sets the number of columns in the model.  If the new size is greater
507      *  than the current size, new columns are added to the end of the model
508      *  with <code>null</code> cell values.
509      *  If the new size is less than the current size, all columns at index
510      *  <code>columnCount</code> and greater are discarded.
511      *
512      *  @param columnCount  the new number of columns in the model
513      *
514      *  @see #setColumnCount
515      * @since 1.3
516      */
517     public void setColumnCount(int columnCount) {
518         columnIdentifiers.setSize(columnCount);
519         justifyRows(0, getRowCount());
520         fireTableStructureChanged();
521     }
522 
523     /**
524      *  Adds a column to the model.  The new column will have the
525      *  identifier <code>columnName</code>, which may be null.  This method
526      *  will send a
527      *  <code>tableChanged</code> notification message to all the listeners.
528      *  This method is a cover for <code>addColumn(Object, Vector)</code> which
529      *  uses <code>null</code> as the data vector.
530      *
531      * @param   columnName the identifier of the column being added
532      */
533     public void addColumn(Object columnName) {
534         addColumn(columnName, (Vector)null);
535     }
536 
537     /**
538      *  Adds a column to the model.  The new column will have the
539      *  identifier <code>columnName</code>, which may be null.
540      *  <code>columnData</code> is the
541      *  optional vector of data for the column.  If it is <code>null</code>
542      *  the column is filled with <code>null</code> values.  Otherwise,
543      *  the new data will be added to model starting with the first
544      *  element going to row 0, etc.  This method will send a
545      *  <code>tableChanged</code> notification message to all the listeners.
546      *
547      * @param   columnName the identifier of the column being added
548      * @param   columnData       optional data of the column being added
549      */
550     public void addColumn(Object columnName, Vector columnData) {
551         columnIdentifiers.addElement(columnName);
552         if (columnData != null) {
553             int columnSize = columnData.size();
554             if (columnSize > getRowCount()) {
555                 dataVector.setSize(columnSize);
556             }
557             justifyRows(0, getRowCount());
558             int newColumn = getColumnCount() - 1;
559             for(int i = 0; i < columnSize; i++) {
560                   Vector row = (Vector)dataVector.elementAt(i);
561                   row.setElementAt(columnData.elementAt(i), newColumn);
562             }
563         }
564         else {
565             justifyRows(0, getRowCount());
566         }
567 
568         fireTableStructureChanged();
569     }
570 
571     /**
572      *  Adds a column to the model.  The new column will have the
573      *  identifier <code>columnName</code>.  <code>columnData</code> is the
574      *  optional array of data for the column.  If it is <code>null</code>
575      *  the column is filled with <code>null</code> values.  Otherwise,
576      *  the new data will be added to model starting with the first
577      *  element going to row 0, etc.  This method will send a
578      *  <code>tableChanged</code> notification message to all the listeners.
579      *
580      * @see #addColumn(Object, Vector)
581      */
582     public void addColumn(Object columnName, Object[] columnData) {
583         addColumn(columnName, convertToVector(columnData));
584     }
585 
586 //
587 // Implementing the TableModel interface
588 //
589 
590     /**
591      * Returns the number of rows in this data table.
592      * @return the number of rows in the model
593      */
594     public int getRowCount() {
595         return dataVector.size();
596     }
597 
598     /**
599      * Returns the number of columns in this data table.
600      * @return the number of columns in the model
601      */
602     public int getColumnCount() {
603         return columnIdentifiers.size();
604     }
605 
606     /**
607      * Returns the column name.
608      *
609      * @return a name for this column using the string value of the
610      * appropriate member in <code>columnIdentifiers</code>.
611      * If <code>columnIdentifiers</code> does not have an entry
612      * for this index, returns the default
613      * name provided by the superclass.
614      */
615     public String getColumnName(int column) {
616         Object id = null;
617         // This test is to cover the case when
618         // getColumnCount has been subclassed by mistake ...
619         if (column < columnIdentifiers.size() && (column >= 0)) {
620             id = columnIdentifiers.elementAt(column);
621         }
622         return (id == null) ? super.getColumnName(column)
623                             : id.toString();
624     }
625 
626     /**
627      * Returns true regardless of parameter values.
628      *
629      * @param   row             the row whose value is to be queried
630      * @param   column          the column whose value is to be queried
631      * @return                  true
632      * @see #setValueAt
633      */
634     public boolean isCellEditable(int row, int column) {
635         return true;
636     }
637 
638     /**
639      * Returns an attribute value for the cell at <code>row</code>
640      * and <code>column</code>.
641      *
642      * @param   row             the row whose value is to be queried
643      * @param   column          the column whose value is to be queried
644      * @return                  the value Object at the specified cell
645      * @exception  ArrayIndexOutOfBoundsException  if an invalid row or
646      *               column was given
647      */
648     public Object getValueAt(int row, int column) {
649         Vector rowVector = (Vector)dataVector.elementAt(row);
650         return rowVector.elementAt(column);
651     }
652 
653     /**
654      * Sets the object value for the cell at <code>column</code> and
655      * <code>row</code>.  <code>aValue</code> is the new value.  This method
656      * will generate a <code>tableChanged</code> notification.
657      *
658      * @param   aValue          the new value; this can be null
659      * @param   row             the row whose value is to be changed
660      * @param   column          the column whose value is to be changed
661      * @exception  ArrayIndexOutOfBoundsException  if an invalid row or
662      *               column was given
663      */
664     public void setValueAt(Object aValue, int row, int column) {
665         Vector rowVector = (Vector)dataVector.elementAt(row);
666         rowVector.setElementAt(aValue, column);
667         fireTableCellUpdated(row, column);
668     }
669 
670 //
671 // Protected Methods
672 //
673 
674     /**
675      * Returns a vector that contains the same objects as the array.
676      * @param anArray  the array to be converted
677      * @return  the new vector; if <code>anArray</code> is <code>null</code>,
678      *                          returns <code>null</code>
679      */
680     protected static Vector convertToVector(Object[] anArray) {
681         if (anArray == null) {
682             return null;
683         }
684         Vector<Object> v = new Vector<Object>(anArray.length);
685         for (Object o : anArray) {
686             v.addElement(o);
687         }
688         return v;
689     }
690 
691     /**
692      * Returns a vector of vectors that contains the same objects as the array.
693      * @param anArray  the double array to be converted
694      * @return the new vector of vectors; if <code>anArray</code> is
695      *                          <code>null</code>, returns <code>null</code>
696      */
697     protected static Vector convertToVector(Object[][] anArray) {
698         if (anArray == null) {
699             return null;
700         }
701         Vector<Vector> v = new Vector<Vector>(anArray.length);
702         for (Object[] o : anArray) {
703             v.addElement(convertToVector(o));
704         }
705         return v;
706     }
707 
708 } // End of class DefaultTableModel